package com.simafei.flow.core.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.simafei.flow.core.common.CalcType;
import com.simafei.flow.core.common.Condition;
import com.simafei.flow.core.common.Conj;
import com.simafei.flow.core.common.Criteria;
import com.simafei.flow.core.common.Criterion;
import com.simafei.flow.core.common.Operator;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author fengpengju
 */
public class ConditionDeserializer extends StdDeserializer<Condition> {

    public static final ConditionDeserializer INSTANCE = new ConditionDeserializer();

    public ConditionDeserializer() {
        super(Condition.class);
    }

    @Override
    public Condition deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
        JsonNode node = context.readTree(jsonParser);
        String type = node.get("type").textValue();

        return switch (type) {
            case "Criterion" -> deserializeCriterion(node);
            case "Criteria" -> deserializeCriteria(node, context);
            default -> throw context.weirdStringException(type, Condition.class, "Unknown Condition type");
        };
    }

    private Criterion deserializeCriterion(JsonNode node) {
        String left = node.get("left").textValue();
        String operatorStr = node.get("operator").textValue();
        Operator operator = Operator.valueOf(operatorStr);
        String right = node.get("right").asText();
        String rightTypeStr = node.get("rightType").textValue();
        CalcType rightType = CalcType.valueOf(rightTypeStr);

        return new Criterion(left, operator, right, rightType);
    }

    private Criteria deserializeCriteria(JsonNode node, DeserializationContext context) throws IOException {
        Conj conj = Conj.valueOf(node.get("conj").textValue().toUpperCase());
        JsonNode conditionsNode = node.get("conditions");
        List<Condition> conditions = new ArrayList<>();

        if (conditionsNode.isArray()) {
            for (JsonNode conditionNode : conditionsNode) {
                conditions.add(deserialize(conditionNode.traverse(), context));
            }
        }
        return Criteria.create(conj, conditions);
    }
}
